#include "commonutil.h"
#ifndef Q_OS_WIN
#include <pthread.h>
#endif
#include "gtime.h"
#include <QTimeZone>

using namespace ns_yht;

CommonUtil::CommonUtil()
{
}

CommonUtil::~CommonUtil()
{
}

void CommonUtil::prtInfo(const QString modeString, const QString varString, const QString valueString)
{
    QDateTime time = QDateTime::currentDateTime();

    QString info = time.toString("yyyy-MM-dd hh:mm:ss");
    info = "[" + info + "]";

    qInfo() << qPrintable(info) << qPrintable(modeString) << qPrintable(varString) << qPrintable(valueString);
}

QString CommonUtil::getMultiNmea(const QString sentence)
{
    int nIndex = 0;
    int nFindIndex = 0;
    QString markString = "*";
    QString bufferString = sentence;
    QString returnString = "";

    bufferString = bufferString.replace("\r", "");
    bufferString = bufferString.replace("\n", "");

    nFindIndex = 0;
    while (nFindIndex >= 0)
    {
        nIndex = bufferString.indexOf(markString);
        if (nIndex >= 0)
        {
            nIndex = nIndex + markString.length() + 2;
            if (nIndex <= bufferString.length())
            {
                nFindIndex = 0;
                if (returnString == "")
                {
                    returnString = bufferString.left(nIndex);
                }
                else
                {
                    returnString = returnString + "\n" + bufferString.left(nIndex);
                }
                bufferString = bufferString.right(bufferString.length() - nIndex);
                bufferString = bufferString.trimmed();
            }
            else
            {
                nFindIndex = -1;
            }
        }
        else
        {
            nFindIndex = -1;
        }
    }
    return returnString;
}

// 将时间字符串转换为utc
// typeInt = 0, timeString = 054109.00
// typeInt = 1, timeString = 054109.000
// typeInt = 2, timeString = 070511054109.00 ddmmyy
qint64 CommonUtil::getUtc(const QString timeString, const int typeInt)
{
    qint64 returnInt = 0;
    QDateTime dateTime = GTime::getUtcTime();
    QString valueString = "";

    if (typeInt == 0)
    {
        valueString = dateTime.toString("yyyy-MM-dd") + " " + timeString.mid(0, 2) + ":" + timeString.mid(2, 2);
        valueString = valueString + ":" + timeString.mid(4, 2); //+ ":" + timeString.mid(7, 2) + "0";
        returnInt = dateTime.fromString(valueString, "yyyy-MM-dd hh:mm:ss").toSecsSinceEpoch();
        returnInt = QDateTime(dateTime.date(), dateTime.time(), QTimeZone::utc()).toSecsSinceEpoch();
    }
    else if (typeInt == 1)
    {
        valueString = dateTime.toString("yyyy-MM-dd") + " " + timeString.mid(0, 2) + ":" + timeString.mid(2, 2);
        valueString = valueString + ":" + timeString.mid(4, 2); // + ":" + timeString.mid(7, 3);
        returnInt = dateTime.fromString(valueString, "yyyy-MM-dd hh:mm:ss").toSecsSinceEpoch();
        returnInt = QDateTime(dateTime.date(), dateTime.time(), QTimeZone::utc()).toSecsSinceEpoch();
    }
    else if (typeInt == 2)
    {
        valueString = dateTime.toString("yyyy-MM-dd");
        valueString = valueString.mid(0, 2) + timeString.mid(4, 2) + "-" + timeString.mid(2, 2) + "-" + timeString.mid(0, 2);
        valueString = valueString + " " + timeString.mid(6, 2) + ":" + timeString.mid(8, 2);
        valueString = valueString + ":" + timeString.mid(10, 2); //+ ":" + timeString.mid(13, 2) + "0";
        returnInt = dateTime.fromString(valueString, "yyyy-MM-dd hh:mm:ss").toSecsSinceEpoch();
        returnInt = QDateTime(dateTime.date(), dateTime.time(), QTimeZone::utc()).toSecsSinceEpoch();
    }

    return returnInt;
}

#if 0
// 将时间字符串转换为utc
// typeInt = 0, timeString = 054109.00
// typeInt = 1, timeString = 054109.000
// typeInt = 2, timeString = 070511054109.00 ddmmyy
qint64 CommonUtil::getUtc(const QString timeString, const int typeInt, const QString zoneDateString, const int zoneDiffInt)
{
    qint64 returnInt = 0;
    QDateTime dateTime;
    QDateTime cTime;
    QString valueString = "";
    QString dateString = "";

    if (zoneDateString == "")
    {
        dateString = dateTime.currentDateTime().toString("yyyy-MM-dd");
    }
    else
    {
        dateString = zoneDateString;
    }

    if (typeInt == 0)
    {
        valueString = dateString + " " + timeString.mid(0, 2) + ":" + timeString.mid(2, 2);
        valueString = valueString + ":" + timeString.mid(4, 2) + ":" + timeString.mid(7, 2) + "0";
    }
    else if (typeInt == 1)
    {
        valueString = dateString + " " + timeString.mid(0, 2) + ":" + timeString.mid(2, 2);
        valueString = valueString + ":" + timeString.mid(4, 2) + ":" + timeString.mid(7, 3);
    }
    else if (typeInt == 2)
    {
        valueString = dateString;
        valueString = valueString.mid(0, 2) + timeString.mid(4, 2) + "-" + timeString.mid(2, 2) + "-" + timeString.mid(0, 2);
        valueString = valueString + " " + timeString.mid(6, 2) + ":" + timeString.mid(8, 2);
        valueString = valueString + ":" + timeString.mid(10, 2) + ":" + timeString.mid(13, 2) + "0";
    }
    cTime = dateTime.fromString(valueString, "yyyy-MM-dd hh:mm:ss:zzz");
    cTime = cTime.addSecs(zoneDiffInt);

    returnInt = cTime.toSecsSinceEpoch();
    qInfo() << "getUtc==========" << timeString << zoneDateString << zoneDiffInt << valueString << cTime;
    return returnInt;
}

QString CommonUtil::getDateTimeString(const qint64 utc, const int typeInt)
{
    QString returnString = "";
    QDateTime dateTime;
    qint64 valueInt = 0;

    if (typeInt == 0)
    {
        // 加上时区
        valueInt = utc + getTimeZoneOffset() * 3600000;
        returnString = dateTime.fromMSecsSinceEpoch(valueInt).toString("yyyy-MM-dd hh:mm:ss");
    }
    else if (typeInt == 1)
    {
        returnString = dateTime.fromMSecsSinceEpoch(utc).toString("yyyy-MM-dd hh:mm:ss");
    }
    return returnString;
}

qint16 CommonUtil::getTimeZoneOffset()
{
    qint16 returnInt = 0;
    QString valueString = "";

    QDateTime localDate = QDateTime::currentDateTime();
    qint64 localInt = localDate.toSecsSinceEpoch();
    // prtInfo("CommonUtil::getTimeZoneOffset", "localInt", QString::number(localInt));

    // fromString("2018-12-11 10:40:00", "yyyy-MM-dd hh:mm:ss");QDateTime::currentDateTimeUtc()
    QDateTime utcDate = localDate.toUTC();
    valueString = utcDate.toString("yyyy-MM-dd hh:mm:ss");
    utcDate = QDateTime::fromString(valueString, "yyyy-MM-dd hh:mm:ss");
    qint64 utcInt = utcDate.toSecsSinceEpoch();
    // prtInfo("CommonUtil::getTimeZoneOffset", "utcInt", QString::number(utcInt));

    returnInt = (localInt - utcInt) / 3600;

    return returnInt;
}
#endif

bool CommonUtil::checkNmeaValid(const QString sentence)
{
    bool returnBool = false;
    QString prefString = sentence.left(1);
    QString suffString = "";
    int valueInt = 0;
    int resultInt = 0;

    if (prefString == "!" || prefString == "$")
    {
        returnBool = true;
    }
    else
    {
        returnBool = false;
    }

    if (returnBool)
    {
        valueInt = sentence.indexOf("*");
        if (valueInt + 3 == sentence.length())
        {
            returnBool = true;
        }
        else
        {
            returnBool = false;
        }
    }

    if (returnBool)
    {
        suffString = sentence.right(2);
        // prtInfo("CommonUtil::checkNmeaValid", "suffString", suffString);
        prefString = sentence.mid(1, sentence.length() - 4);
        // prtInfo("CommonUtil::checkNmeaValid", "prefString", prefString);
        QByteArray byteArray = prefString.toLatin1();

        resultInt = static_cast<int>(byteArray.at(0));
        for (int i = 1; i < byteArray.length(); i++)
        {
            valueInt = static_cast<int>(byteArray.at(i));
            resultInt = resultInt ^ valueInt;
        }
        prefString = QString::number(resultInt, 16);
        prefString = prefString.toUpper();
        // prtInfo("CommonUtil::checkNmeaValid", "prefString", prefString);

        if (prefString == suffString)
        {
            returnBool = true;
        }
        else
        {
            returnBool = false;
        }
    }
    return returnBool;
}

QString CommonUtil::trimLeft(const QString sentence, const QString markString)
{
    QString returnString = "";
    int indexInt = sentence.indexOf(markString);

    if (indexInt > 0)
    {
        returnString = sentence.right(sentence.length() - indexInt);
    }
    else
    {
        returnString = sentence;
    }
    return returnString;
}

int CommonUtil::getSignedInt(const QString valueString, const int bitNumberInt)
{
    int returnInt = 0;

    int valueInt = valueString.toInt(nullptr, 2);
    int baseInt = qPow(2, bitNumberInt);

    if (valueString.mid(0, 1) == "1")
    {
        returnInt = valueInt - baseInt;
    }
    else
    {
        returnInt = valueInt;
    }

    return returnInt;
}

QString CommonUtil::getWeekString(int dayofweek)
{
    switch (dayofweek)
    {
    case 0:
        return "星期日";
    case 1:
        return "星期一";
    case 2:
        return "星期二";
    case 3:
        return "星期三";
    case 4:
        return "星期四";
    case 5:
        return "星期五";
    case 6:
        return "星期六";
    default:
        return "";
    }
}

#if 0

// 将经纬度数值转换为字符串
// typeInt = 0, lonlatDouble = ，单位为度
// typeInt = 1, lonlatDouble = 054109.000

QString CommonUtil::getLonlatString(const double lonlatDouble, const int typeInt)
{
    QString returnString = "";
    int degreeInt = qFloor(lonlatDouble);
    double minuteDouble = (lonlatDouble - degreeInt) * 60;

    if (typeInt == 0)
    {
        returnString = QString::number(degreeInt) + "°" + QString::number(minuteDouble) + "'";
    }
    else if (typeInt == 1)
    {
        int minuteInt = qFloor(minuteDouble);
        double secondDouble = (minuteDouble - minuteInt) * 60;
        returnString = QString::number(degreeInt) + "°" + QString::number(minuteInt) + "'" + QString::number(secondDouble) + "'";
    }
    else
    {
        int minuteInt = qFloor(minuteDouble);
        double secondDouble = (minuteDouble - minuteInt) * 60;
        int secondInt = qFloor(secondDouble);
        double rentDouble = secondDouble - secondInt;
        returnString = QString("%1°%2'%3'.%4").arg(degreeInt).arg(minuteInt).arg(secondInt).arg(rentDouble);
    }

    return returnString;
}

// 将字符串转换为经纬度数值
// typeInt = 0, lonlatString = ddmm.mmmm或者ddmm.mmm
// typeInt = 1, timeString = dddmm.mmmm或者dddmm.mmm

double CommonUtil::getLonlat(const QString lonlatString, const int typeInt)
{
    double returnDoubl = 0;
    int degreeInt = 0;
    int lengthInt = 0;
    double minuteDouble = 0;

    if (typeInt == 0)
    {
        degreeInt = lonlatString.left(2).toInt();
        lengthInt = lonlatString.length() - 2;
        minuteDouble = lonlatString.mid(2, lengthInt).toDouble();
        returnDoubl = degreeInt + minuteDouble / 60.0;
    }
    else if (typeInt == 1)
    {
        degreeInt = lonlatString.left(3).toInt();
        lengthInt = lonlatString.length() - 3;
        minuteDouble = lonlatString.mid(3, lengthInt).toDouble();
        returnDoubl = degreeInt + minuteDouble / 60.0;
    }

    return returnDoubl;
}

bool CommonUtil::isCoorValid(qreal lat, qreal lon)
{
    return (lat > -90 && lat <= 90 && lon > -180 && lon <= 180);
}

bool CommonUtil::isCoorValid(const QPair<double, double> &coor)
{
    return isCoorValid(coor.first, coor.second);
}

double CommonUtil::convertCoordinateToDouble(const QString &strcoor)
{
    double coor = 0;
    QStringList listcoor = strcoor.split(QString::fromLocal8Bit("°"));

    coor = listcoor[0].toDouble();
    if (listcoor.count() > 1)
    {
        listcoor = listcoor[1].split(QString::fromLocal8Bit("′"));
        coor += listcoor[0].toDouble() / 60.0;
        if (listcoor.count() > 1)
        {
            QString scoor = listcoor[1].replace(QString::fromLocal8Bit("″"), "").replace("E", "").replace("N", "").replace("S", "").replace("W", "");
            coor += scoor.toDouble() / 3600.0;
        }
    }

    return coor;
}

QString CommonUtil::convertCoordinateToString(double coor, int dnum, bool isLon, bool ignoreMinus, const QString &sd, const QString &sm, const QString &ss)
{
    if (isLon)
    {
        if (coor > 180)
            return "--";
    }
    else
    {
        if (coor > 90)
            return "--";
    }

    QString strcoor;
    bool isNegative = coor < 0;
    if (isNegative)
        coor = coor * (-1);
    int degree = qFloor(coor);
    coor -= degree;
    coor *= 60.0;
    int minute = qFloor(coor);
    if (coor > 59.99)
    {
        minute = 0;
        degree++;
        coor = 0;
    }
    coor -= minute;
    coor *= 60;
    // prevent to :122_23_60.0
    if (coor > 59.948)
    {
        minute++;
        coor = 0;
    }
    QString strDegree = QString("%1").arg(degree, isLon ? 3 : 2, 10, QLatin1Char('0'));
    QString strMinute = QString("%1").arg(minute, 2, 10, QLatin1Char('0'));
    int second1 = qFloor(coor);
    int second2 = static_cast<int>((coor - second1) * qPow(10, dnum));
    QString strSecond1 = QString("%1").arg(second1, 2, 10, QLatin1Char('0'));
    QString strSecond2 = QString("%1").arg(second2, dnum, 10, QLatin1Char('0'));
    //    strcoor = strDegree+QString::fromLocal8Bit("°")+strMinute+QString::fromLocal8Bit("′")+strSecond1+(dnum>0?("."+strSecond2):"")+QString::fromLocal8Bit("″");
    strcoor = strDegree + sd + strMinute + sm + strSecond1 + (dnum > 0 ? ("." + strSecond2) : "") + ss;
    if (!ignoreMinus)
    {
        if (isNegative)
        {
            if (isLon)
                strcoor = "-" + strcoor + "W";
            else
                strcoor = "-" + strcoor + "S";
        }
        else
        {
            if (isLon)
                strcoor = strcoor + "E";
            else
                strcoor = strcoor + "N";
        }
    }

    return strcoor;
}

QString CommonUtil::convertCoordinate(double coor, int dnum, bool isLon, bool ignoreMinus, const QString &sd, const QString &sm)
{
    QString strcoor;
    bool isNegative = coor < 0;
    if (isNegative)
        coor = coor * (-1);
    int degree = qFloor(coor);
    coor -= degree;
    coor *= 60.0;

    if (coor > 59.94)
    {

        degree++;
        coor = 0;
    }

    QString strDegree = QString("%1").arg(degree, isLon ? 3 : 2, 10, QLatin1Char('0'));
    QString strMinute = QString("%1").arg(coor, 0, 'f', 2, QLatin1Char('0'));

    strcoor = strDegree + sd + strMinute + sm; //+strSecond1+(dnum>0?("."+strSecond2):"")+QString::fromLocal8Bit("″");
    if (!ignoreMinus)
    {
        if (isNegative)
        {
            if (isLon)
                strcoor = "-" + strcoor + "W";
            else
                strcoor = "-" + strcoor + "S";
        }
        else
        {
            if (isLon)
                strcoor = strcoor + "E";
            else
                strcoor = strcoor + "N";
        }
    }

    return strcoor;
}

// 0-度分秒(1位小数)，1-度分(4位小数)，2-度(7位小数)
void CommonUtil::convertCoordinate(double coor, int &degree, int &minute, int &second, int &decimal, int format)
{
    //    bool isNegative=coor<0;
    coor = qAbs(coor);
    degree = qFloor(coor);
    coor -= degree;

    if (format == 2)
    {
        decimal = static_cast<int>(coor * 10000000);
        if (decimal == 10000000)
        {
            decimal = 0;
            degree++;
        }

        return;
    }

    coor *= 60.0;
    minute = qFloor(coor);
    coor -= minute;

    if (format == 1)
    {
        decimal = static_cast<int>(coor * 10000);
        if (decimal == 10000)
        {
            decimal = 0;
            minute++;
            if (minute == 60)
            {
                minute = 0;
                degree++;
            }
        }

        return;
    }

    coor *= 60.0;
    second = qFloor(coor);
    coor -= second;

    decimal = static_cast<int>(coor * 10);
    if (decimal == 10)
    {
        decimal = 0;
        second++;
        if (second == 60)
        {
            second = 0;
            minute++;
            if (minute == 60)
            {
                minute = 0;
                degree++;
            }
        }
    }
    return;
}

#endif

bool CommonUtil::floatEqual(double a, double b, double err)
{
    return (qAbs(a - b) < err);
}

QString CommonUtil::getSpeedString(double speed)
{
    return speed < 0 ? "--" : (QString::number(speed, 'f', 1) + " Kn");
}

QString CommonUtil::getAngleString(double angle)
{
    return (angle > 510 || angle < -360) ? "--" : QString::number(angle, 'f', 1) + " °";
}

QString CommonUtil::getTcpaString(double tcpa)
{
    if ((qIsNaN(tcpa) || qIsInf(tcpa) || tcpa < 0))
        return ("--");
    else
    {
        int m = qFloor(tcpa);
        int s = qRound((tcpa - m) * 60);
        if (s == 0)
            return (QString::number(m) + (" 分"));
        else
            return (QString::number(m) + (" 分 ") + QString::number(s) + " 秒");
    }
}

QString CommonUtil::getDistanceString(double distance)
{
    if ((qIsNaN(distance) || qIsInf(distance) || distance < 0))
        return "--";
    else
    {
        if (distance >= 1852)
            return (QString::number(distance / 1852, 'f', 1) + (" Nm"));
        else
            return (QString::number(distance, 'f', 1) + (" M"));
    }
}

double CommonUtil::getDcpaFromIndex(int index)
{
    switch (index)
    {
    case 0:
        return 2;
    case 1:
        return 1;
    case 2:
        return 0.5;
    case 3:
        return 0.3;
    case 4:
        return 0.1;
    default:
        return 0;
    }
}

double CommonUtil::getTcpaFromIndex(int index)
{
    switch (index)
    {
    case 0:
        return 20;
    case 1:
        return 15;
    case 2:
        return 10;
    case 3:
        return 5;
    default:
        return 0;
    }
}

int CommonUtil::getDutyAlarmTimeFromIndex(int index)
{
    // 0-20m 1-15m 2-10m 3-5m
    switch (index)
    {
    case 0:
        return 20;
    case 1:
        return 15;
    case 2:
        return 10;
    case 3:
        return 5;
    default:
        return 0;
    }
}
